package de.westranger.forex.trading.analysis;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import de.westranger.forex.trading.analysis.util.EvaluationResult;
import de.westranger.forex.trading.genetic.CSVBasedContentResolver;
import de.westranger.forex.trading.genetic.ContentResolver;
import de.westranger.forex.trading.genetic.allel.fitness.ProfitManager;
import de.westranger.forex.trading.genetic.allel.operator.TerminalSymbol;

public final class SREvaluation {
	private static final boolean LOG = true;
	
	public static void main(String[] args) throws IOException, ParseException {
		final ContentResolver conRes = new CSVBasedContentResolver("E:\\MT4_vlidation_data\\ema_train_0.csv.gz");
		//final ContentResolver conRes = new CSVBasedContentResolver("./data/mql_validation_java_indicator_0.csv.gz");
		/*final BufferedWriter bw = new BufferedWriter(new FileWriter("log.txt"));

		System.out.println("windowLen\tdenom\tchan\tstop\ttake\ttrue\tfalse\tprofit");
		for(int windowLength:new int[]{10,20,30,40,50,60,70,80,90,100,200,300,400,500,600,700,800,900,1000,2000}){
			for(int denominator:new int[]{3,4,5,6,7,8,9,10}){
						for(double channel:new double[]{0.9,0.95,0.99}){
							final int gapLen = windowLength/denominator;
							EvaluationResult eval = computeSRChances(conRes,windowLength,gapLen,channel,0.0,0.0);
							final String str = eval.toString();
							bw.write(str);
							System.out.print(str);							
						}
			}
		}
		bw.close();
		*/

		// ################################		
		EvaluationResult eval = computeSRChances(conRes,20,20/5,0.95,-300.0,300.0);
		final String str = eval.toString();
		System.out.println(str);
				
	}
	
	private static EvaluationResult computeSRChances(final ContentResolver conRes, final int windowLength, final int gapLen, final double channel,final double stopLoss, final double takeProfit){
		final double[] yValues = new double[windowLength];
		final double[] xValues = new double[yValues.length];
		final int append = (int)(windowLength*(1.0/3.0));
		final EvaluationResult eval = new EvaluationResult(windowLength,gapLen,channel,stopLoss,takeProfit);
		final ProfitManager pro = new ProfitManager(conRes, 50.0, 0.1, stopLoss, 1000.0,takeProfit);
		double total = 0.0;
		// variables needed for evaluation
		int lastPic = 0;
		int ruleTrue = 0;
		int ruleFalse = 0;
		
		for(int i=0;i< yValues.length;i++){
			xValues[i] = i;
		}
		
		for (int i = windowLength; i < conRes.getValueCount()-append; i++) {		

			for (int j = 0; j < windowLength; j++) {
				yValues[j] = conRes.resolve(TerminalSymbol.HIGH.getValue(), i - windowLength + j);
			}

			final double[] result = LinearRegression.computeRegression(xValues, yValues);
			final double[] norm = LinearRegression.normalize(xValues, yValues, result);
			
			double min = Double.MAX_VALUE;
			double max = Double.MIN_VALUE;
			int countSupport = 0;
			int countResistance = 0;
			int gapSupport = 0;
			int gapResistance = 0;
			
			
			for(double x:norm){
				min = Math.min(min, x);
				max = Math.max(max, x);
			}

			final XYSeries series4 = new XYSeries("S/R Points");

			final StringBuilder sx = new StringBuilder();
			
			for(int j=0;j<norm.length;j++){
				if(norm[j] <= min*channel && gapSupport >= gapLen){
					if(LOG){
						series4.add(j, yValues[j]);						
					}
					countSupport++;
					gapSupport = 0;
					sx.append('s');
				}
				if(norm[j] >= max*channel && gapResistance >= gapLen){
					if(LOG){
						series4.add(j, yValues[j]);						
					}
					countResistance++;
					gapResistance = 0;
					sx.append('r');
				}
				gapSupport++;
				gapResistance++;
			}

			if((countSupport >= 3 && gapSupport < windowLength*0.1) || (countResistance >= 3 && gapResistance < windowLength*0.1)){
				if(i-lastPic > 1){
					
					if(countSupport >= 3){
						System.out.println("gap sup:" + gapSupport);
					}else{
						System.out.println("gap res:" + gapResistance);
					}
					
					double minSeries = Double.MAX_VALUE;
					double maxSeries = Double.MIN_VALUE;
					
					for(double x:yValues){
						minSeries = Math.min(minSeries, x);
						maxSeries = Math.max(maxSeries, x);
					}
					
					String label = null;
					double profit = pro.pendingBuyOrder(i, i+append);
					
					if(profit > 0.0){
						label = "buy";
					}else{
						profit = pro.pendingSellOrder(i, i+append);
					
						if(profit > 0.0){
							label = "sell";
						}else{
							label = "nothing";
						}
					}

					final double angle = Math.toDegrees(Math.atan(result[1])); 
					System.out.println(sx.toString()+";"+countSupport+";"+countResistance+";"+gapSupport+";"+gapResistance+";"+angle+";"+label);
					
					// ###################################################################
					final double[] chanMin = new double[]{result[0]+(min*1.01),result[1]};
					final double[] chanMax = new double[]{result[0]+(max*1.01),result[1]}; 
					
			        final XYSeries series1 = new XYSeries("Forex Data");
			        final XYSeries series2 = new XYSeries("Support Line");
			        final XYSeries series3 = new XYSeries("Resistance Line");
			        final XYSeriesCollection dataset = new XYSeriesCollection();
			        
			        if(LOG){
				        for(int x=0;x<windowLength;x++){
				        	series1.add(x, yValues[x]);
				        	series2.add(x, LinearRegression.linearFunction(x, chanMin));
				        	series3.add(x, LinearRegression.linearFunction(x, chanMax));
				        }
			
				        final XYSeries series5 = new XYSeries("Forex continue");
				        for(int j=0;j<=append;j++){
				        	series5.add(j+windowLength-1,conRes.resolve(TerminalSymbol.HIGH.getValue(), i + j-1));
				        	series2.add(windowLength+j, LinearRegression.linearFunction(windowLength+j, chanMin));
				        	series3.add(windowLength+j, LinearRegression.linearFunction(windowLength+j, chanMax));
				        }
				        
						dataset.addSeries(series1);
						dataset.addSeries(series2);
						dataset.addSeries(series3);
						dataset.addSeries(series4);
						dataset.addSeries(series5);
			        }
			        
			        // now we need to find out if 'rule' hold or not
			        final double oldMin = minSeries;
			        final double oldMax = maxSeries;
			        minSeries = Double.MAX_VALUE;
					maxSeries = Double.MIN_VALUE;
			        for(int j=0;j<=append;j++){
						minSeries = Math.min(minSeries, conRes.resolve(TerminalSymbol.HIGH.getValue(), i + j));
						maxSeries = Math.max(maxSeries, conRes.resolve(TerminalSymbol.LOW.getValue(), i + j));
			        }

			        System.out.println("~~ "+ (conRes.resolve(TerminalSymbol.HIGH.getValue(), i)-maxSeries));
			        System.out.println("~~ "+ (conRes.resolve(TerminalSymbol.LOW.getValue(), i)-minSeries));
			        
			        double cutSupport = 0;
			        double cutResistance = 0;
			        for(int j=0;j<=append;j++){
			        	if(conRes.resolve(TerminalSymbol.HIGH.getValue(), i + j) > LinearRegression.linearFunction(windowLength+j, chanMax)){
			        		cutResistance++;
			        	}

			        	if(conRes.resolve(TerminalSymbol.HIGH.getValue(), i + j) < LinearRegression.linearFunction(windowLength+j, chanMin)){
			        		cutSupport++;
			        	}
			        }

			        if(countSupport >= 3){
			        	if(cutSupport <= append*0.1){
			        		ruleTrue++;
			        	}else{
			        		ruleFalse++;	
			        	}
			        }else{
			        	if(cutResistance <= append*0.1){
			        		ruleTrue++;
			        	}else{
			        		ruleFalse++;	
			        	}
			        }

			        minSeries = Math.min(minSeries, oldMin);
			        maxSeries = Math.max(maxSeries, oldMax);
			        
			        final StringBuilder sb = new StringBuilder();
					
					sb.append(conRes.resolve(TerminalSymbol.TIME.getValue(), i));
					sb.append('\t');
					sb.append(conRes.resolve(TerminalSymbol.HIGH.getValue(), i));
					sb.append('\t');
					
					if(countSupport >= 3){
						sb.append(countSupport);
					}
					sb.append('\t');
					if(countResistance >= 3){
						sb.append(countResistance);
					}
					sb.append('\t');
					sb.append(ruleTrue);
					sb.append('\t');
					sb.append(ruleFalse);
					
					if(LOG){
						System.out.println(sb.toString().replace('.', ','));
						final JFreeChart chart = ChartFactory.createXYLineChart(sb.toString(), "", "", dataset, PlotOrientation.VERTICAL, true, true, false);
						final XYPlot plot1 = (XYPlot) chart.getPlot();
						plot1.getRangeAxis().setRange(minSeries-0.001, maxSeries+0.001);

						XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
						renderer.setSeriesShapesVisible(0, false);
						renderer.setSeriesShapesVisible(1, false);
						renderer.setSeriesShapesVisible(2, false);
						renderer.setSeriesLinesVisible(3, false);
						renderer.setSeriesShapesVisible(4, false);

						plot1.setRenderer(renderer);
						try {
							ChartUtilities.saveChartAsJPEG(new File("./out/plot_r"+countResistance+"_s"+countSupport+"_"+i+".jpg"), chart, 1400, 800);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				lastPic = i;
			}
		}
		eval.setPosTrade(ruleTrue);
		eval.setNegTrade(ruleFalse);
		eval.setProfit(total);
		return eval;
	}
	

}
